﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Compiler.CompilerAPI;
using ConceptsParser.Parser;
using Compiler.TableOfSymbols;
using Compiler.SyntaxTreeAnalysis;

namespace Compiler
{
    /// <summary>
    /// Объект компилятора для программы с концептами
    /// </summary>
    public class ConceptsCompiler
    {
        /// <summary>
        /// Набор используемых библиотек
        /// </summary>
        private HashSet<DllLibInfo> usedDLLs;

        public ConceptsCompiler()
        {
            usedDLLs = new HashSet<DllLibInfo>();
        }

        public bool ContainsDLL(string dllFileName)
        {
            /*var result = usedDLLs.FirstOrDefault((DllLibInfo dllInfo) 
                => dllInfo.FileName == dllFileName);
            return result != null;*/
            return usedDLLs.Contains(new DllLibInfo(dllFileName));
        }

        public void AddDLL(string dllFileName)
        {
            usedDLLs.Add(new DllLibInfo(dllFileName));
        }

        public void RemoveDLL(string dllFileName)
        {
            usedDLLs.Remove(new DllLibInfo(dllFileName));
        }

        /// <summary>
        /// Компилирует программу с текстом programCode
        /// </summary>
        /// <param name="programCode">Текст программы</param>
        /// <returns>Результат компиляции</returns>
        public CompilationResult Compile(string programCode)
        {
            CompilationResult result;
            try
            {
                Parser parser;
                bool ok = _Parse(programCode, out parser);
                if (!ok)
                {
                    result = new CompilationResult(false);
                    if (parser.ToolsManager.HasSyntaxErrors)
                        result.AddError(parser.ToolsManager.FirstSyntaxError.ToString());
                    return result;
                }
                CompilationEnvironment environment;
                ok = _CheckTypes(parser, out environment);
                if (!ok)
                {
                    result = new CompilationResult(false);
                    foreach (SemanticError error in environment.ErrorManager.SemanticErrors)
                        result.AddError(error.ToString());
                }
                else
                {
                    result = new CompilationResult(true);
                }
                foreach (Warning warning in environment.ErrorManager.Warnings)
                    result.AddWarning(warning.ToString());
                foreach (DebugInfo message in environment.ErrorManager.DebugMessages)
                    result.AddDebugMessage(message.ToString());
                return result;
            }
            catch (Exception exc)
            {
                result = new CompilationResult(false);
                result.SetExceptionError(exc.ToString());
            }
            return result;
        }

        /// <summary>
        /// Создаёт парсер для программы
        /// </summary>
        /// <param name="programCode">Текст программы</param>
        private bool _Parse(string programCode, out Parser parser)
        {
            ConceptsParser.Scanner.Scanner scanner = new ConceptsParser.Scanner.Scanner();
            scanner.SetSource(programCode, 0);
            parser = new Parser(scanner);
            return parser.Parse();
        }

        private bool _CheckTypes(Parser parser, out CompilationEnvironment environment)
        {
            environment = new CompilationEnvironment(usedDLLs);
            GeneralSemanticVisitor visitor = new GeneralSemanticVisitor(environment);
            visitor.Visit(parser.root);
            return !environment.ErrorManager.HasSemanticErrors;
        }
    }
}
